package cn.cool.service.impl;

import cn.cool.dto.UserRegisterDTO;
import cn.cool.entity.Article;
import cn.cool.entity.User;
import cn.cool.mapper.ArticleMapper;
import cn.cool.mapper.UserMapper;
import cn.cool.result.ResponseResult;
import cn.cool.service.UserService;
import cn.cool.utils.JWTUtils;
import cn.cool.utils.RedisUtil;
import cn.cool.utils.UploadUtils;
import cn.cool.vo.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.tomcat.util.http.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author LiuH
 * @since 2021-01-23
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ArticleMapper articleMapper;
    //qq邮箱格式  大于5 小于等于11
    private static final String EMAIL_FORMAT = "[1-9]\\d{5,10}@qq\\.com";
    //电话号码格式
    private static final String PHONE_FORMAT = "^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$";

    /**
     * 登录
     *
     * @param user
     * @return
     */
    @Override
    public Object login(User user) {

        if (user.getUserAccount() == null
                || user.getUserAccount().trim().length() == 0) {//判断登录账号是否为空 或 " "

            return ResponseResult.failure("请输入登录账号");

        } else if (user.getUserPassword() == null
                || user.getUserPassword().trim().length() == 0) {//判断密码是否为空 或 " "

            return ResponseResult.failure("请输入密码");

        }



        UserInfoVo userdb = userMapper.selectByAccountAndPassword(user);

        if (userdb != null) {
            //将发表的文章数量、关注量、粉丝量放入实体类
            userdb.setArticleCount(getArticleCount(userdb.getUserId()));
            userdb.setFollowCount(redisUtil.sMember("follow:"+userdb.getUserId()));
            userdb.setFansCount(redisUtil.sMember("fans:"+userdb.getUserId()));
            //将数据库查询出来的数据放入 payload
            HashMap<String, String> payload = new HashMap<>();
            payload.put("userId", String.valueOf(userdb.getUserId()));
            payload.put("userName", userdb.getUserName());

            //生成token
            String token = JWTUtils.getToken(payload);
            //将token放入redis 设置过期时间 7 天 单位 秒  key--> token:userId
            redisUtil.set("token:" + userdb.getUserId(), token, 604800L);
            //用户信息到缓存hash中 key--> userinfo item: userId  存储时间跟token时间同步
            redisUtil.hset("userInfo",""+userdb.getUserId(),userdb,redisUtil.getExpire("token:"+userdb.getUserId()));

            return ResponseResult.success(200, "登录成功", userdb, token);

        } else {
            return ResponseResult.failure("账号或密码错误");
        }
    }

    /**
     * 注册
     *
     * @param user
     * @return
     */
    @Override
    public Object register(UserRegisterDTO user) {

        //防止用户传" "
        if (user.getUserName() == null
                || user.getUserName().trim().length() == 0) {//判断用户名是否为空 或 " "

            return ResponseResult.failure("请输入正确的用户名");

        } else if (user.getUserAccount() == null
                || user.getUserAccount().trim().length() == 0) {//判断登录账号是否为空 或 " "

            return ResponseResult.failure("请输入登录账号");

        } else if (user.getUserPassword() == null
                || user.getUserPassword().trim().length() == 0) {//判断密码是否为空 或 " "

            return ResponseResult.failure("请输入密码");

        } else if (user.getUserEmail() == null
                || user.getUserEmail().trim().length() == 0
                || !user.getUserEmail().matches(EMAIL_FORMAT)) {//判断邮箱是否符合格式 是否为空 或 " "

            return ResponseResult.failure("邮箱格式有误或为空");

        } else if (user.getUserPhone() == null
                || user.getUserPhone().trim().length() == 0
                || !user.getUserPhone().matches(PHONE_FORMAT)) {//判断手机号码是否符合格式 是否为空 或 " "

            return ResponseResult.failure("手机号码格式有误或为空");

        }

        // 检查账号、邮箱、电话 是否 存在
        if (checkAccount(user.getUserAccount())) {
            return ResponseResult.failure("账号已存在");
        }
        if (checkEmail(user.getUserEmail())) {
            return ResponseResult.failure("邮箱已存在");
        }
        if (checkPhone(user.getUserPhone())) {
            return ResponseResult.failure("电话号码已存在");
        }

        //从缓存中获取验证码
        List<Object> randomCodeList = redisUtil.lGet("randomCode", 0, -1);
        //比对
        if (!randomCodeList.contains(user.getRandomCode())) {
            return ResponseResult.failure("验证码错误!");
        }
        //创建时间
        user.setGmtCreate(new Date());

        //插入数据库 返回 主键id
        int rs = userMapper.userRegister(user);
        if (rs > 0) {
            //将用户账号/邮箱/电话添加至缓存 key-->xxx:userId
            redisUtil.sSet("user_account", user.getUserAccount());
            redisUtil.sSet("user_email", user.getUserEmail());
            redisUtil.sSet("user_phone", user.getUserPhone());
            return ResponseResult.success(200, "注册成功!即将跳转到登录页");
        }

        return ResponseResult.failure("注册失败,请重新试试吧");

    }

    /**
     * 退出登录
     *
     * @param request
     * @return
     */
    @Override
    public Object logOut(HttpServletRequest request) {
        Integer userId = JWTUtils.getUserId(request);
        //删除redis中的 token 键
        redisUtil.del("token:" + userId);
        //删除用户信息缓存
        redisUtil.hdel("userInfo",""+userId);

        return ResponseResult.success(200, "退出成功");
    }

    /**
     * 用户修改信息
     *
     * @param user
     * @return
     */
    @Override
    public Object setUserInfo(HttpServletRequest request, User user, MultipartFile file) {
        //不为null 说明用户设置的是这个属性
        //设置 用户头像或背景图时 前端携带多一个 当前属性的空字符串 防止进不了判断
        if (user.getUserAvatar() != null) {
            return setUserAvatar(request, user, file);
        } else if (user.getBackgroundImg() != null) {
            return setBackgroundImg(request, user, file);
        } else if (user.getUserName() != null) {
            return setUserName(request, user);
        } else if (user.getUserEmail() != null) {
            return setUserEmail(request, user);
        } else if (user.getUserPhone() != null) {
            return setUserPhone(request, user);
        } else if (user.getUserSex() != null) {
            return setUserSex(request, user);
        } else if (user.getUserSign() != null) {
            return setUserSign(request, user);
        }
        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 设置用户头像
     *
     * @param request
     * @param user
     * @param file
     * @return
     */
    private Object setUserAvatar(HttpServletRequest request, User user, MultipartFile file) {

        String avatarName = null;

        User newUser = updateSettings(request, user);
        //图片存到数据库的格式 路径+文件名
        newUser.setUserAvatar("/images/avatar/" + avatarName);

        try {
            //获取缓存中的用户对象
            User cacheUser = (User) redisUtil.get("user:" + newUser.getUserId());
            //如果头像不是默认值 则删除原本的头像
            if (!"/images/avatar/default.jpg".equals(cacheUser.getUserAvatar())) {
                UploadUtils.deleteImg(cacheUser.getUserAvatar());
            }
            //上传图片到 static/images/avatar目录下
            avatarName = UploadUtils.upload(file, "avatar");
        } catch (FileNotFoundException e) {
            return "文件不存在!";
        }

        //更新数据库
        boolean isUpdate = this.updateById(newUser);

        if (isUpdate) {
            //刷新缓存中用户信息
            refreshCache("user_avatar", newUser.getUserId(), newUser.getUserAvatar());
            return ResponseResult.success(200, "修改成功");
        }
        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 设置个人背景图
     *
     * @param request
     * @param user
     * @return
     */
    private Object setBackgroundImg(HttpServletRequest request, User user, MultipartFile file) {
        String backgroundImageName = null;

        User newUser = updateSettings(request, user);
        //图片存到数据库的格式 路径+文件名
        newUser.setBackgroundImg("/images/backgroundImg/" + backgroundImageName);

        try {
            //获取缓存中的用户对象
            User cacheUser = (User) redisUtil.get("user:" + newUser.getUserId());
            //如果背景图不是默认值 则删除原本的背景图
            if (!"/images/backgroundImg/bgd_default.jpg".equals(cacheUser.getBackgroundImg())) {
                UploadUtils.deleteImg(cacheUser.getBackgroundImg());
            }
            //上传图片到 static/images/background目录下
            backgroundImageName = UploadUtils.upload(file, "backgroundImg");
        } catch (FileNotFoundException e) {
            return "文件不存在!";
        }

        //更新数据库
        boolean isUpdate = this.updateById(newUser);

        if (isUpdate) {
            //刷新缓存中用户信息
            refreshCache("background_img", newUser.getUserId(), newUser.getBackgroundImg());
            return ResponseResult.success(200, "修改成功");
        }
        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 设置用户名
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserName(HttpServletRequest request, User user) {
        //防止用户传" "
        if (user.getUserName() == null
                || user.getUserName().trim().length() == 0) {//判断用户名是否为空 或 " "

            return ResponseResult.failure("请输入正确的用户名");

        }

        //给user实体 id 修改时间  赋值
        User newUser = updateSettings(request, user);
        //更新数据库
        boolean isUpdate = this.updateById(newUser);

        if (isUpdate) {
            //刷新缓存中用户信息
            refreshCache("user_name", newUser.getUserId(), newUser.getUserName());
            return ResponseResult.success(200, "修改成功");
        }
        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");

    }

    /**
     * 设置用户邮箱
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserEmail(HttpServletRequest request, User user) {
        //防止用户传" "
        if (user.getUserEmail() == null
                || user.getUserEmail().trim().length() == 0
                || !user.getUserEmail().matches(EMAIL_FORMAT)) {//判断邮箱是否符合格式 是否为空 或 " "

            return ResponseResult.failure("邮箱格式有误或为空");

        }
        //给user实体 id 修改时间  赋值
        User newUser = updateSettings(request, user);

        //邮箱查重
        if (checkEmail(user.getUserEmail())) {
            return ResponseResult.failure("邮箱已存在,请重新换一个试试吧!");
        }
        //更新数据库
        boolean isUpdate = this.updateById(newUser);
        if (isUpdate) {
            //将新设置的邮箱放入缓存并刷新缓存中用户信息
            refreshCache("user_email", newUser.getUserId(), newUser.getUserEmail());
            return ResponseResult.success(200, "修改成功");
        }
        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 设置用户手机号
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserPhone(HttpServletRequest request, User user) {
        //防止用户传" "
        if (user.getUserPhone() == null
                || user.getUserPhone().trim().length() == 0
                || !user.getUserPhone().matches(PHONE_FORMAT)) {//判断手机号码是否符合格式 是否为空 或 " "

            return ResponseResult.failure("手机号码格式有误或为空");

        }

        //给user实体 id 修改时间  赋值
        User newUser = updateSettings(request, user);

        //电话号码查重
        if (checkPhone(user.getUserPhone())) {
            return ResponseResult.failure("电话号码已存在,请重新换一个试试吧!");
        }
        //更新数据库
        boolean isUpdate = this.updateById(newUser);

        if (isUpdate) {
            //将新设置的电话号码放入缓存并刷新缓存中用户信息
            refreshCache("user_phone", newUser.getUserId(), newUser.getUserPhone());
            return ResponseResult.success(200, "修改成功");
        }

        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 设置用户性别
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserSex(HttpServletRequest request, User user) {

        //性别只有两个选项 不需要判断

        //给user实体 id 修改时间  赋值
        User newUser = updateSettings(request, user);

        //更新数据库
        boolean isUpdate = this.updateById(newUser);

        if (isUpdate) {
            //刷新缓存中用户信息
            refreshCache("user_sex", newUser.getUserId(), newUser.getUserSex());
            return ResponseResult.success(200, "修改成功");
        }

        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 设置用户生日
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserBirth(HttpServletRequest request, User user) {
        //TODO setUserBirth待定
        return null;
    }

    /**
     * 设置用户所属城市
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserAddr(HttpServletRequest request, User user) {
        //TODO setUserAddr待定
        return null;
    }

    /**
     * 设置个性签名
     *
     * @param request
     * @param user
     * @return
     */
    private Object setUserSign(HttpServletRequest request, User user) {
        //个性签名 可以为空 限定字数为 40
        if (user != null && user.getUserSign().length() > 40) {
            return ResponseResult.failure("个性签名字数不能超过40噢~");
        }

        //给user实体 id 修改时间  赋值
        User newUser = updateSettings(request, user);
        //更新数据库
        boolean isUpdate = this.updateById(newUser);

        if (isUpdate) {
            //刷新缓存中用户信息
            refreshCache("user_sign", newUser.getUserId(), newUser.getUserSign());
            return ResponseResult.success(200, "修改成功");
        }

        // 不知道返回啥了 随便整整
        return ResponseResult.failure("网络异常,请稍后试试");
    }

    /**
     * 检查登录账号是否已存在 true-存在 false-不存在
     *
     * @param user_account
     * @return
     */
    private boolean checkAccount(String user_account) {
        boolean hasKey = redisUtil.sHasKey("user_account", user_account);
        return hasKey;
    }

    /**
     * 检查邮箱是否已存在 true-存在 false-不存在
     *
     * @param user_email
     * @return
     */
    private boolean checkEmail(String user_email) {
        boolean hasKey = redisUtil.sHasKey("user_email", user_email);
        return hasKey;
    }

    /**
     * 检查电话号码是否已存在 true-存在 false-不存在
     *
     * @param user_phone
     * @return
     */
    private boolean checkPhone(String user_phone) {
        boolean hasKey = redisUtil.sHasKey("user_phone", user_phone);
        return hasKey;
    }

    /**
     * 更新时调用--->  设置用户id 和 修改时间
     *
     * @param user
     * @return
     */
    private User updateSettings(HttpServletRequest request, User user) {
        Integer userId = JWTUtils.getUserId(request);
        user.setUserId(userId);
        user.setGmtModified(new Date());
        return user;
    }

    /**
     * 设置新值到缓存 移除旧的值
     *
     * @param key    缓存键 / 数据库字段名
     * @param userId 用户id
     * @param value  设置的新值
     */
    private void refreshCache(String key, Integer userId, Object value) {
        // TODO refreshCache未完善

        //从缓存中获取旧的user值
        UserInfoVo cacheUser = (UserInfoVo) redisUtil.hget("userInfo",""+userId);

        //除了 邮箱 电话 之外的值只需要刷新缓存中对象的值
        if ("user_avatar".equals(key)) {
            cacheUser.setUserAvatar((String) value);
        } else if ("background_img".equals(key)) {
            cacheUser.setBackgroundImg((String) value);
        } else if ("user_name".equals(key)) {
            cacheUser.setUserName((String) value);
        } else if ("user_email".equals(key)) {
            //移除缓存中的旧值
            long l = redisUtil.setRemove(key, cacheUser.getUserEmail());
            //修改的值更新到对象中
            cacheUser.setUserEmail((String) value);
            //添加新值到缓存
            redisUtil.sSet(key, value);
        } else if ("user_phone".equals(key)) {
            //移除缓存中的旧值
            long l = redisUtil.setRemove(key, cacheUser.getUserPhone());
            //修改的值更新到对象中
            cacheUser.setUserPhone((String) value);
            //添加新值到缓存
            redisUtil.sSet(key, value);
        } else if ("user_sex".equals(key)) {
            cacheUser.setUserSex((Integer) value);
        } else if ("user_sign".equals(key)) {
            cacheUser.setUserSign((String) value);
        }

        //刷新 缓存中 用户对象的值 存储时间跟token时间同步
        redisUtil.hset("userInfo",""+userId,cacheUser,redisUtil.getExpire("token:"+userId));

    }

    /**
     * 获取用户发表的文章总数
     * @param userId
     * @return
     */
    private Integer getArticleCount(Integer userId){
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.eq("author_id",userId);
        return articleMapper.selectCount(wrapper);
    }

}